package com.org.shichui.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * jdk zip包解压缩
 *
 * @author fanlinglong
 * @date 2018年07月12日 11:11
 */
public class ZipUtil {
    private static Logger LOG = LoggerFactory.getLogger(ZipUtil.class);

    /**
     * 缓冲器大小
     */
    private static final int BUFFER = 512;

    /**
     * 创建文件
     * 根据压缩包内文件名和解压缩目的路径，创建解压缩目标文件，
     * 生成中间目录
     *
     * @param dstPath  解压缩目的路径
     * @param fileName 压缩包内文件名
     * @return 解压缩目标文件
     * @throws IOException
     */
    private static File createFile(String dstPath, String fileName) throws IOException {
        String[] dirs = fileName.split("/");//将文件名的各级目录分解
        File file = new File(dstPath);

        if (dirs.length > 1) {//文件有上级目录
            for (int i = 0; i < dirs.length - 1; i++) {
                file = new File(file, dirs[i]);//依次创建文件对象知道文件的上一级目录
            }

            if (!file.exists()) {
                file.mkdirs();//文件对应目录若不存在，则创建
                LOG.info("mkdirs: " + file.getCanonicalPath());
            }

            file = new File(file, dirs[dirs.length - 1]);//创建文件

            return file;
        } else {
            if (!file.exists()) {
                file.mkdirs();//若目标路径的目录不存在，则创建
                LOG.info("mkdirs: " + file.getCanonicalPath());
            }

            file = new File(file, dirs[0]);//创建文件

            return file;
        }
    }

    /**
     * 解压缩方法
     *
     * @param zipFileName 压缩文件名
     * @param dstPath     解压目标路径
     * @return
     */
    public static Map<String, Object> unzip(String zipFileName, String dstPath) {
        LOG.info("zip uncompressing...");

        Map<String, Object> map = new HashMap<>();
        List<String> filePaths = new ArrayList<>();

        map.put("success", true);
        map.put("filePaths", filePaths);

        try {
            ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zipFileName), Charset.forName("GBK"));
            ZipEntry zipEntry = null;
            byte[] buffer = new byte[BUFFER];//缓冲器
            int readLength = 0;//每次读出来的长度

            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                if (zipEntry.isDirectory()) {//若是zip条目目录，则需创建这个目录
                    File dir = new File(dstPath + "/" + zipEntry.getName());

                    if (!dir.exists()) {
                        dir.mkdirs();
                        LOG.info("mkdirs: " + dir.getCanonicalPath());

                        continue;//跳出
                    }
                }

                File file = createFile(dstPath, zipEntry.getName());//若是文件，则需创建该文件

//                LOG.debug("file created: " + file.getCanonicalPath());

                OutputStream outputStream = new FileOutputStream(file);

                while ((readLength = zipInputStream.read(buffer, 0, BUFFER)) != -1) {
                    outputStream.write(buffer, 0, readLength);
                }

                outputStream.close();
                filePaths.add(file.getCanonicalPath());

//                LOG.debug("file uncompressed: " + file.getCanonicalPath());

            }    // end while
        } catch (FileNotFoundException e) {
            map.put("success", false);
            e.printStackTrace();
            LOG.error(e.getMessage());
            LOG.error("unzip fail!");
        } catch (IOException e) {
            map.put("success", false);
            e.printStackTrace();
            LOG.error(e.getMessage());
            LOG.error("unzip fail!");
        }

        LOG.info("unzip success!");

        return map;
    }


    public static void main(String[] args) {
        String zipFilePath = "D:\\ziptest\\zipPath\\test.zip";
        String unzipFilePath = "D:\\ziptest\\zipPath";
        try {
            unzip(zipFilePath, unzipFilePath + "\\aaaaa");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
